package cn.latenight.http;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class GetBarrage {

    private static int av;
    private static int cid;
    private static String title;
    private static String path;
    private static Elements element_barrages;
    private static File fileBarrage;
    private static File fileVideo;
    private static GetVideo getVideo;
    private static boolean is_fileBarrage;

    public static void getAid(){

        System.out.println((char)27 + "[36m>>> 开始组装视频uri >>>" + (char)27 + "[30m");
        System.out.print((char)27 + "[33m[TIPS] 请输入视频av号：" + (char)27 + "[30m");
        Scanner scanner = new Scanner(System.in);
        av = scanner.nextInt();
        getVideoHtml();
    }

    public static void getVideoHtml(){

        String uri = "https://www.bilibili.com/video/av" + av;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(uri);
        CloseableHttpResponse httpResponse = null;
        httpGet.addHeader("User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36");
        System.out.println("[INFO] 准备向网页发起" + httpGet.getMethod() + "请求：" + uri);

        try {
            httpResponse = httpClient.execute(httpGet);
            if (httpResponse.getStatusLine().getStatusCode() == 200) {
                System.out.println((char)27 + "[32m[SUCCESS] 响应成功！响应行状态码：[" + httpResponse.getStatusLine().getStatusCode() + "]" + (char)27 + "[30m");
                HttpEntity httpEntity = httpResponse.getEntity();
                String html = EntityUtils.toString(httpEntity,"utf-8");
                System.out.println("[INFO] 网页：" + uri + "响应体爬取完成");
                getOid(html);
            } else {
                System.err.println("[ERROR] 响应失败！响应行状态码：[" + httpResponse.getStatusLine().getStatusCode() + "]");
                System.err.println("[ERROR] 网页：" + uri + "爬取失败！");
                System.err.print("[ERROR] 程序结束");
            }
        } catch (IOException e){
            e.printStackTrace();
        } finally {
            try {
                httpResponse.close();
            } catch (IOException e){
                e.printStackTrace();
            }
        }
    }

    public static void getOid(String html){

        System.out.println((char)27 + "[36m\n>>> 开始提取视频数据 >>>" + (char)27 + "[30m");
        Document document = Jsoup.parse(html);
        Element element_title = document.selectFirst("h1.video-title");
        title = element_title.text();

        /*如果视频没有显示日排行榜排名*/
        //Element element_data = document.selectFirst("div.video-data").select("span").last();
        /*如果视频显示了日排行榜排名*/
        Element element_data = document.selectFirst("div.video-data").select("span").get(1);
        String data = element_data.text();
        Element element_name = document.selectFirst("a.username");
        String name = element_name.text();

        System.out.println("[INFO] 视频标题：" + title);
        System.out.println("[INFO] 发布时间：" + data);
        System.out.println("[INFO] UP主昵称：" + name);
        if (title.length() > 30){
            title = title.substring(0, 30);
        }

        // "cid=" + player.cid + "&aid=" + player.aid      cid=*****&aid=   cid=[0-9]{1,}&aid=
        String regex1 = "cid=[0-9]{1,}&aid=";
        String regex2 = "[0-9]{1,}";
        Pattern pattern = Pattern.compile(regex1);
        Matcher matcher = pattern.matcher(html);
        if (matcher.find()) {
            html = matcher.group();
        }
        pattern = Pattern.compile(regex2);
        matcher = pattern.matcher(html);
        if (matcher.find()) {
            html = matcher.group();
        }

        cid = Integer.parseInt(html);
        System.out.println("[INFO] 视频及弹幕标识符cid和oid：" + cid);


        getBarrageHtml(cid);
    }

    public static void getBarrageHtml(int oid){

        System.out.println((char)27 + "[36m\n>>> 开始组装弹幕uri >>>" + (char)27 + "[30m");
        String uri = "https://api.bilibili.com/x/v1/dm/list.so?oid=" + oid;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(uri);
        CloseableHttpResponse httpResponse = null;
        httpGet.addHeader("User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36");
        System.out.println("[INFO] 准备向网页发起" + httpGet.getMethod() + "请求：" + uri);

        try {
            httpResponse = httpClient.execute(httpGet);
            if (httpResponse.getStatusLine().getStatusCode() == 200) {
                System.out.println((char)27 + "[32m[SUCCESS] 响应成功！响应行状态码：[" + httpResponse.getStatusLine().getStatusCode() + "]" + (char)27 + "[30m");
                HttpEntity httpEntity = httpResponse.getEntity();
                String html = EntityUtils.toString(httpEntity,"utf-8");
                System.out.println("[INFO] 网页：" + uri + "响应体爬取完成");
                getBarrage(html);
            } else {
                System.err.println("[ERROR] 响应失败！响应行状态码：[" + httpResponse.getStatusLine().getStatusCode() + "]");
                System.err.println("[ERROR] 网页：" + uri + "爬取失败！");
                System.err.print("[ERROR] 程序结束");
            }
        } catch (IOException e){
            e.printStackTrace();
        } finally {
            try {
                httpResponse.close();
            } catch (IOException e){
                e.printStackTrace();
            }
        }
    }

    public static void getBarrage(String html){

        System.out.println((char)27 + "[36m\n>>> 开始提取弹幕数据 >>>" + (char)27 + "[30m");
        Document document = Jsoup.parse(html);
        element_barrages = document.select("d");
        System.out.print((char)27 + "[33m[TIPS] 弹幕内容已获取，是否将内容写入硬盘文件？（y/n）：" + (char)27 + "[30m");
        Scanner scanner = new Scanner(System.in);
        String flag = "";
        while (true){
            flag = scanner.next();
            if (flag.equals("y") || flag.equals("n")){
                break;
            } else {
                System.err.print("[ERROR] 请正确输入！（\"y\" or \"n\"）：");
            }
        }

        if (flag.equals("y")){
            is_fileBarrage = true;
            createFile();
        } else {
            is_fileBarrage = false;
            System.out.println((char)27 + "[35m\n******************************弹幕列表如下******************************");
            for (Element element : element_barrages){
                System.out.println(element.text());
            }
            System.out.println((char)27 + "[35m***********************************************************************" + (char)27 + "[30m");
            System.out.println("\n[INFO] 弹幕内容已全部输出");
            createFile();
            //System.err.print("[EXIT] 程序结束");
        }

    }

    public static void createFile(){

        System.out.println((char)27 + "[36m\n>>> 开始创建本地硬盘文件 >>>" + (char)27 + "[30m");
        Scanner scanner = new Scanner(System.in);
        System.out.print((char)27 + "[33m[TIPS] 请输入本地硬盘文件目录：" + (char)27 + "[30m");
        path = scanner.next();

        if (is_fileBarrage){
            // /Users/macbookpro/Desktop
            fileBarrage = new File(path + "/" + title + ".txt");
            if (fileBarrage.exists()){
                System.out.println("[INFO] 弹幕文件已存在，路径为：" + fileBarrage.getPath());
            } else {
                System.out.println("[INFO] 弹幕文件不存在，开始创建文件");
                try {
                    if (fileBarrage.createNewFile()){
                        System.out.println((char)27 + "[32m[SUCCESS] 弹幕文件创建成功！路径为：" + fileBarrage.getPath() + (char)27 + "[30m");
                    } else {
                        System.err.print("[ERROR] 弹幕文件创建失败！");
                        //System.err.print("[ERROR] 程序结束");
                        System.exit(0);
                    }
                } catch (IOException e){
                    e.printStackTrace();
                }
            }
        }

        fileVideo = new File(path + "/" + title + ".flv");
        if (fileVideo.exists()){
            System.out.println("[INFO] 视频文件已存在，路径为：" + fileVideo.getPath());
        } else {
            System.out.println("[INFO] 视频文件不存在，开始创建文件");
            try {
                if (fileVideo.createNewFile()){
                    System.out.println((char)27 + "[32m[SUCCESS] 视频文件创建成功！路径为：" + fileVideo.getPath() + (char)27 + "[30m");
                } else {
                    System.err.print("[ERROR] 视频文件创建失败！");
                    //System.err.print("[ERROR] 程序结束");
                    System.exit(0);
                }
            } catch (IOException e){
                e.printStackTrace();
            }
        }
        writeFile(fileBarrage);
    }

    public static void writeFile(File file){

        if (is_fileBarrage){
            System.out.println((char)27 + "[36m\n>>> 开始将弹幕写入文件 >>>" + (char)27 + "[30m");
            FileWriter fw = null;
            BufferedWriter bw = null;
            try {
                System.out.println("[INFO] 开始创建字符输出流");
                fw = new FileWriter(file);
                System.out.println("[INFO] 开始创建输出缓冲流");
                bw = new BufferedWriter(fw);
                for (Element element : element_barrages){
                    bw.write(element.text() + "\n");
                }
                bw.flush();
                System.out.println((char)27 + "[32m[SUCCESS] 弹幕内容已全部写入文件中！" + (char)27 + "[30m");
                getVideo = new GetVideo(cid, av, fileVideo);
                //System.err.println("[ERROR] 程序结束");
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    bw.close();
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        getVideo = new GetVideo(cid, av, fileVideo);
    }

    public static void main(String[] args) {
        getAid();
    }
}
